#ifndef __RTCSsocket_H__
#define __RTCSsocket_H__

#include "RTCSbaseObject.h"

#ifdef _SOLARIS
#include <assert.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/filio.h>
#include <netdb.h>
#ifndef	INADDR_NONE
#define	INADDR_NONE	0xffffffff
#endif
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1
#define WSAEINVAL EINVAL
#define WSAEMSGSIZE EMSGSIZE
#else
#include <winsock.h>
#ifdef VC
#pragma comment(lib, "wsock32.lib")
#endif
#endif

#define SHUT_RD     0
#define SHUT_WR     1
#define SHUT_RDWR   2

#define RTCS_FD_READ     0x0001
#define RTCS_FD_WRITE    0x0002
#define RTCS_FD_OOB      0x0004
#define RTCS_FD_ACCEPT   0x0008
#define RTCS_FD_CONNECT  0x0010
#define RTCS_FD_CLOSE    0x0020

#ifdef _SOLARIS
typedef struct sockaddr_in SOCKADDR_IN;
typedef struct sockaddr SOCKADDR;
typedef unsigned short WORD;
typedef int SOCKET;
typedef struct hostent HOSTENT;
typedef struct hostent * LPHOSTENT;
typedef struct in_addr * LPIN_ADDR;
#endif

//##ModelId=3AAC612001C3
class RTCS_Socket
{
public:
	//##ModelId=3AAC6120032B
	static RTCS_CTbool InitSocket();
	//##ModelId=3AAC61200322
	static void TerminateSocket();
	//##ModelId=3AAC61200321
	RTCS_Socket();
	//##ModelId=3AAC61200319
	virtual ~RTCS_Socket();
	//##ModelId=3AAC6120030F
	RTCS_CTbool Create(unsigned int nSocketPort = 0, int nSocketType=SOCK_STREAM, LPCTSTR lpszSocketAddress = NULL);

	RTCS_CTbool CreateBroadcast(unsigned int nSocketPort = 20000);

	//##ModelId=3AAC612002FB
	RTCS_CTbool GetSockName(RTCS_CTstring& rSocketAddress, unsigned int& rSocketPort);
	//##ModelId=3AAC61200305
	RTCS_CTbool GetSockName(SOCKADDR* lpSockAddr, int* lpSockAddrLen);

	//##ModelId=3AAC612002EF
	RTCS_CTbool SetSockOpt(int nOptionName, const void* lpOptionValue, int nOptionLen, int nLevel = SOL_SOCKET);
	//##ModelId=3AAC612002DC
	RTCS_CTbool GetSockOpt(int nOptionName, void* lpOptionValue, int* lpOptionLen, int nLevel = SOL_SOCKET);

	//##ModelId=3AAC612002DB
	static int GetLastError();
	//##ModelId=3AAC612002D2
	static void SetLastError(int err);

	//##ModelId=3AAC612002C7
	virtual RTCS_CTbool Accept(RTCS_Socket& rConnectedSocket, SOCKADDR* lpSockAddr = NULL, int* lpSockAddrLen = NULL);
	//##ModelId=3AAC612002BF
	virtual void Close();

	//##ModelId=3AAC612002AB
	RTCS_CTbool Connect(LPCTSTR lpszHostAddress, unsigned int nHostPort);
	//##ModelId=3AAC612002B5
	RTCS_CTbool Connect(const SOCKADDR* lpSockAddr, int nSockAddrLen);

	//##ModelId=3AAC612002A1
	RTCS_CTbool IOCtl(long lCommand, RTCS_CTuint* lpArgument);

	//##ModelId=3AAC6120029F
	RTCS_CTbool Listen(int nConnectionBacklog=5);

	//##ModelId=3AAC6120028E
	virtual int Receive(void* lpBuf, int nBufLen, int nFlags = 0);

	//##ModelId=3AAC6120026D
	int ReceiveFrom(void* lpBuf, int nBufLen, RTCS_CTstring& rSocketAddress, unsigned int& rSocketPort, int nFlags = 0);
	//##ModelId=3AAC61200281
	int ReceiveFrom(void* lpBuf, int nBufLen, SOCKADDR* lpSockAddr, int* lpSockAddrLen, int nFlags = 0);

	//##ModelId=3AAC61200264
	RTCS_CTbool ShutDown(int nHow = SHUT_WR);

	//##ModelId=3AAC61200259
	virtual int Send(const void* lpBuf, int nBufLen, int nFlags = 0);

	//##ModelId=3AAC61200232
	int SendTo(const void* lpBuf, int nBufLen, unsigned int nHostPort, LPCTSTR lpszHostAddress = NULL, int nFlags = 0);
	//##ModelId=3AAC61200246
	int SendTo(const void* lpBuf, int nBufLen, const SOCKADDR* lpSockAddr, int nSockAddrLen, int nFlags = 0);

	//##ModelId=3AAC61200229
	RTCS_CTbool AsyncSelect(long lEvent = RTCS_FD_READ|RTCS_FD_WRITE|RTCS_FD_OOB|RTCS_FD_ACCEPT|RTCS_FD_CONNECT|RTCS_FD_CLOSE);

	//##ModelId=3AAC612001ED
	SOCKET m_hSocket;

protected:
	//##ModelId=3AAC61200227
	virtual void OnReceive(int nErrorCode);
	//##ModelId=3AAC6120021E
	virtual void OnSend(int nErrorCode);
	//##ModelId=3AAC61200214
	virtual void OnOutOfBandData(int nErrorCode);
	//##ModelId=3AAC6120020B
	virtual void OnAccept(int nErrorCode);
	//##ModelId=3AAC61200209
	virtual void OnConnect(int nErrorCode);
	//##ModelId=3AAC61200200
	virtual void OnClose(int nErrorCode);

private:	
	//##ModelId=3AAC612001FF
	RTCS_CTuint DoAcceptRun();
	//##ModelId=3AAC612001F6
	RTCS_CTuint DoReadRun();
	//##ModelId=3AAC612001F5
	RTCS_CTuint DoUDPReadRun();

	//##ModelId=3AAC612001DC
	RTCS_Thread*	thread;

	//##ModelId=3AAC612001CD
	friend RTCS_CTuint do_SocketAcceptRun(RTCS_Socket* socket)
	{
		return socket ? socket->DoAcceptRun() : RTCS_Error_ECTF_Fail;
	}
	//##ModelId=3AAC612001CF
	friend RTCS_CTuint do_SocketReadRun(RTCS_Socket* socket)
	{
		return socket ? socket->DoReadRun() : RTCS_Error_ECTF_Fail;
	}
	//##ModelId=3AAC612001D8
	friend RTCS_CTuint do_UDPSocketReadRun(RTCS_Socket* socket)
	{
		return socket ? socket->DoUDPReadRun() : RTCS_Error_ECTF_Fail;
	}
};


/**************************\
** inline implementations **
\**************************/

inline int RTCS_Socket::GetLastError() 
{ 
#ifdef _SOLARIS
	return errno;
#else
	return WSAGetLastError(); 
#endif
}

inline void RTCS_Socket::SetLastError(int err) 
{ 
#ifdef _SOLARIS
	errno = err;
#else
	WSASetLastError(err); 
#endif
}

#endif

